home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / dosfile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-02  |  24.7 KB  |  1,144 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* DOS file handling routines */
  8.  
  9. #include "mint.h"
  10.  
  11. static long do_dup P_((int,int));
  12. static void unselectme P_((PROC *));
  13.  
  14. /*
  15.  * first, some utility routines
  16.  */
  17.  
  18. FILEPTR *
  19. do_open(name, rwmode, attr, x)
  20.     const char *name;    /* file name */
  21.     int rwmode;    /* file access mode */
  22.     int attr;    /* TOS attributes for created files (if applicable) */
  23.     XATTR *x;    /* filled in with attributes of opened file */
  24. {
  25.     struct tty *tty;
  26.     fcookie dir, fc;
  27.     long devsp;
  28.     FILEPTR *f;
  29.     DEVDRV *dev;
  30.     long r;
  31.     XATTR xattr;
  32.     unsigned perm;
  33.     int creating;
  34.     char temp1[PATH_MAX];
  35.     extern FILESYS proc_filesys;
  36.  
  37. /* for special BIOS "fake" devices */
  38.     extern DEVDRV fakedev;
  39.  
  40.     TRACE(("do_open(%s)", name));
  41.  
  42. /*
  43.  * first step: get a cookie for the directory
  44.  */
  45.  
  46.     r = path2cookie(name, temp1, &dir);
  47.     if (r) {
  48.         mint_errno = (int)r;
  49.         DEBUG(("do_open(%s): error %ld", name, r));
  50.         return NULL;
  51.     }
  52.  
  53. /*
  54.  * second step: try to locate the file itself
  55.  */
  56.     r = relpath2cookie(&dir, temp1, follow_links, &fc, 0);
  57.  
  58. /*
  59.  * file found: this is an error if (O_CREAT|O_EXCL) are set
  60.  */
  61.  
  62.     if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
  63.         DEBUG(("do_open(%s): file already exists",name));
  64.         mint_errno = EACCDN;
  65.         release_cookie(&fc);
  66.         release_cookie(&dir);
  67.         return NULL;
  68.     }
  69. /*
  70.  * file not found: maybe we should create it
  71.  * note that if r != 0, the fc cookie is invalid (so we don't need to
  72.  * release it)
  73.  */
  74.     if (r == EFILNF && (rwmode & O_CREAT)) {
  75.     /* check first for write permission in the directory */
  76.         r = (*dir.fs->getxattr)(&dir, &xattr);
  77.         if (r == 0) {
  78.             if (denyaccess(&xattr, S_IWOTH))
  79.                 r = EACCDN;
  80.         }
  81.         if (r) {
  82.             DEBUG(("do_open(%s): couldn't get "
  83.                   "write permission on directory",name));
  84.             mint_errno = (int)r;
  85.             release_cookie(&dir);
  86.             return NULL;
  87.         }
  88.         r = (*dir.fs->creat)(&dir, temp1,
  89.             (S_IFREG|DEFAULT_MODE) & (~curproc->umask), attr, &fc);
  90.         if (r) {
  91.             DEBUG(("do_open(%s): error %ld while creating file",
  92.                 name, r));
  93.             mint_errno = (int)r;
  94.             release_cookie(&dir);
  95.             return NULL;
  96.         }
  97.         creating = 1;
  98.     } else if (r) {
  99.         DEBUG(("do_open(%s): error %ld while searching for file",
  100.             name, r));
  101.         mint_errno = (int)r;
  102.         release_cookie(&dir);
  103.         return NULL;
  104.     } else {
  105.         creating = 0;
  106.     }
  107.  
  108. /*
  109.  * check now for permission to actually access the file
  110.  */
  111.     r = (*fc.fs->getxattr)(&fc, &xattr);
  112.     if (r) {
  113.         DEBUG(("do_open(%s): couldn't get file attributes",name));
  114.         mint_errno = (int)r;
  115.         release_cookie(&dir);
  116.         release_cookie(&fc);
  117.         return NULL;
  118.     }
  119. /*
  120.  * we don't do directories
  121.  */
  122.     if ( (xattr.mode & S_IFMT) == S_IFDIR ) {
  123.         DEBUG(("do_open(%s): file is a directory",name));
  124.         release_cookie(&dir);
  125.         release_cookie(&fc);
  126.         mint_errno = EFILNF;
  127.         return NULL;
  128.     }
  129.  
  130.     switch (rwmode & O_RWMODE) {
  131.     case O_WRONLY:
  132.         perm = S_IWOTH;
  133.         break;
  134.     case O_RDWR:
  135.         perm = S_IROTH|S_IWOTH;
  136.         break;
  137.     case O_EXEC:
  138.         perm = (fc.fs->fsflags & FS_NOXBIT) ? S_IROTH : S_IXOTH;
  139.         break;
  140.     case O_RDONLY:
  141.         perm = S_IROTH;
  142.         break;
  143.     default:
  144.         perm = 0;
  145.         ALERT("do_open: bad file access mode: %x", rwmode);
  146.     }
  147.     if (!creating && denyaccess(&xattr, perm)) {
  148.         DEBUG(("do_open(%s): access to file denied",name));
  149.         release_cookie(&dir);
  150.         release_cookie(&fc);
  151.         mint_errno = EACCDN;
  152.         return NULL;
  153.     }
  154.  
  155. /*
  156.  * an extra check for write access -- even the superuser shouldn't
  157.  * write to files with the FA_RDONLY attribute bit set (unless,
  158.  * we just created the file, or unless the file is on the proc
  159.  * file system and hence FA_RDONLY has a different meaning)
  160.  */
  161.     if ( !creating && (xattr.attr & FA_RDONLY) && fc.fs != &proc_filesys) {
  162.         if ( (rwmode & O_RWMODE) == O_RDWR ||
  163.              (rwmode & O_RWMODE) == O_WRONLY ) {
  164.             DEBUG(("do_open(%s): can't write a read-only file",
  165.                 name));
  166.             release_cookie(&dir);
  167.             release_cookie(&fc);
  168.             mint_errno = EACCDN;
  169.             return NULL;
  170.         }
  171.     }
  172.  
  173. /*
  174.  * if writing to a setuid or setgid file, clear those bits
  175.  */
  176.     if ( (perm & S_IWOTH) && (xattr.mode & (S_ISUID|S_ISGID)) ) {
  177.         xattr.mode &= ~(S_ISUID|S_ISGID);
  178.         (*fc.fs->chmode)(&fc, (xattr.mode & ~S_IFMT));
  179.     }
  180. /*
  181.  * If the caller asked for the attributes of the opened file, copy them over.
  182.  */
  183.     if (x) *x = xattr;
  184.  
  185. /*
  186.  * So far, so good. Let's get the device driver now, and try to
  187.  * actually open the file.
  188.  */
  189.     dev = (*fc.fs->getdev)(&fc, &devsp);
  190.     if (!dev) {
  191.         mint_errno = (int)devsp;
  192.         DEBUG(("do_open(%s): device driver not found",name));
  193.         release_cookie(&dir);
  194.         release_cookie(&fc);
  195.         return NULL;
  196.     }
  197.  
  198.     if (dev == &fakedev) {        /* fake BIOS devices */
  199.         f = curproc->handle[devsp];
  200.         if (!f) {
  201.             mint_errno = EIHNDL;
  202.             return 0;
  203.         }
  204.         f->links++;
  205.         release_cookie(&dir);
  206.         release_cookie(&fc);
  207.         return f;
  208.     }
  209.     if (0 == (f = new_fileptr())) {
  210.         release_cookie(&dir);
  211.         release_cookie(&fc);
  212.         mint_errno = ENSMEM;
  213.         return NULL;
  214.     }
  215.     f->links = 1;
  216.     f->flags = rwmode;
  217.     f->pos = 0;
  218.     f->devinfo = devsp;
  219.     f->fc = fc;
  220.     f->dev = dev;
  221.     release_cookie(&dir);
  222.  
  223.     r = (*dev->open)(f);
  224.     if (r < 0) {
  225.         DEBUG(("do_open(%s): device open failed with error %ld",
  226.             name, r));
  227.         mint_errno = (int)r;
  228.         f->links = 0;
  229.         release_cookie(&fc);
  230.         dispose_fileptr(f);
  231.         return NULL;
  232.     }
  233.  
  234. /* special code for opening a tty */
  235.     if (is_terminal(f)) {
  236.         extern struct tty default_tty;    /* in tty.c */
  237.  
  238.         tty = (struct tty *)f->devinfo;
  239.         if (tty->use_cnt == 0) {     /* first open for this device? */
  240.             *tty = default_tty;
  241.         }
  242.         tty->use_cnt++;
  243.     }
  244.     return f;
  245. }
  246.  
  247. /*
  248.  * helper function for do_close: this closes the indicated file pointer which
  249.  * is assumed to be associated with process p. The extra parameter is necessary
  250.  * because f_midipipe mucks with file pointers of other processes, so
  251.  * sometimes p != curproc.
  252.  *
  253.  * Note that the function changedrv() in filesys.c can call this routine.
  254.  * in that case, f->dev will be 0 to represent an invalid device, and
  255.  * we cannot call the device close routine.
  256.  */
  257.  
  258. long
  259. do_pclose(p, f)
  260.     PROC *p;
  261.     FILEPTR *f;
  262. {
  263.     long r = 0;
  264.  
  265.     if (!f) return EIHNDL;
  266.  
  267. /* if this file is "select'd" by this process, unselect it
  268.  * (this is just in case we were killed by a signal)
  269.  */
  270.  
  271. /* BUG? Feature? If media change is detected while we're doing the select,
  272.  * we'll never unselect (since f->dev is set to NULL by changedrv())
  273.  */
  274.     if (f->dev) {
  275.         (*f->dev->unselect)(f, (long)p, O_RDONLY);
  276.         (*f->dev->unselect)(f, (long)p, O_WRONLY);
  277.     }
  278.  
  279.     f->links--;
  280.  
  281. /* TTY manipulation must be done *before* calling the device close routine,
  282.  * since afterwards the TTY structure may no longer exist
  283.  */
  284.     if (is_terminal(f) && f->links <= 0) {
  285.         struct tty *tty = (struct tty *)f->devinfo;
  286.         tty->use_cnt--;
  287.         if (tty->use_cnt <= 0)
  288.             tty->pgrp = 0;
  289.         if (tty->use_cnt <= 0 && tty->xkey) {
  290.             kfree(tty->xkey);
  291.             tty->xkey = 0;
  292.         }
  293.     }
  294.  
  295.     if (f->dev) {
  296.         r = (*f->dev->close)(f, p->pid);
  297.         if (r) {
  298.             DEBUG(("close: device close failed"));
  299.         }
  300.     }
  301.     if (f->links <= 0) {
  302.         release_cookie(&f->fc);
  303.         dispose_fileptr(f);
  304.     }
  305.     return  r;
  306. }
  307.  
  308. long
  309. do_close(f)
  310.     FILEPTR *f;
  311. {
  312.     return do_pclose(curproc, f);
  313. }
  314.  
  315. long ARGS_ON_STACK
  316. f_open(name, mode)
  317.     const char *name;
  318.     int mode;
  319. {
  320.     int i;
  321.     FILEPTR *f;
  322.     PROC *proc;
  323.  
  324.     TRACE(("Fopen(%s, %x)", name, mode));
  325. #if O_GLOBAL
  326.     if (mode & O_GLOBAL) {
  327.         /* oh, boy! user wants us to open a global handle! */
  328.         proc = rootproc;
  329.     }
  330.     else
  331. #endif
  332.         proc = curproc;
  333.  
  334.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  335.         if (!proc->handle[i])
  336.             goto found_for_open;
  337.     }
  338.     DEBUG(("Fopen(%s): process out of handles",name));
  339.     return ENHNDL;        /* no more handles */
  340.  
  341. found_for_open:
  342.     mode &= O_USER;        /* make sure the mode is legal */
  343.  
  344. /* note: file mode 3 is reserved for the kernel; for users, transmogrify it
  345.  * into O_RDWR (mode 2)
  346.  */
  347.     if ( (mode & O_RWMODE) == O_EXEC ) {
  348.         mode = (mode & ~O_RWMODE) | O_RDWR;
  349.     }
  350.  
  351.     f = do_open(name, mode, 0, (XATTR *)0);
  352.  
  353.  
  354.     if (!f) {
  355.         return mint_errno;
  356.     }
  357.     proc->handle[i] = f;
  358. /* default is to close non-standard files on exec */
  359.     proc->fdflags[i] = FD_CLOEXEC;
  360.  
  361. #if O_GLOBAL
  362.     if (proc != curproc) {
  363.         /* we just opened a global handle */
  364.         i += 100;
  365.     }
  366. #endif
  367.  
  368.     TRACE(("Fopen: returning %d", i));
  369.     return i;
  370. }
  371.  
  372. long ARGS_ON_STACK
  373. f_create(name, attrib)
  374.     const char *name;
  375.     int attrib;
  376. {
  377.     fcookie dir;
  378.     int i;
  379.     FILEPTR *f;
  380.     long r;
  381.     PROC *proc;
  382.     int offset = 0;
  383.     char temp1[PATH_MAX];
  384.  
  385.     TRACE(("Fcreate(%s, %x)", name, attrib));
  386. #if O_GLOBAL
  387.     if (attrib & O_GLOBAL) {
  388.         proc = rootproc;
  389.         offset = 100;
  390.         attrib &= ~O_GLOBAL;
  391.     }
  392.     else
  393. #endif
  394.         proc = curproc;
  395.  
  396.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  397.         if (!proc->handle[i])
  398.             goto found_for_create;
  399.     }
  400.     DEBUG(("Fcreate(%s): process out of handles",name));
  401.     return ENHNDL;        /* no more handles */
  402.  
  403. found_for_create:
  404.     if (attrib == FA_LABEL) {
  405.         r = path2cookie(name, temp1, &dir);
  406.         if (r) return r;
  407.         r = (*dir.fs->writelabel)(&dir, temp1);
  408.         release_cookie(&dir);
  409.         if (r) return r;
  410. /*
  411.  * just in case the caller tries to do something with this handle,
  412.  * make it point to u:\dev\null
  413.  */
  414.         f = do_open("u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0,
  415.                  (XATTR *)0);
  416.         proc->handle[i] = f;
  417.         proc->fdflags[i] = FD_CLOEXEC;
  418.         return i+offset;
  419.     }
  420.     if (attrib & (FA_LABEL|FA_DIR)) {
  421.         DEBUG(("Fcreate(%s,%x): illegal attributes",name,attrib));
  422.         return EACCDN;
  423.     }
  424.  
  425.     f = do_open(name, O_RDWR|O_CREAT|O_TRUNC, attrib, (XATTR *)0);
  426.  
  427.     if (!f) {
  428.         DEBUG(("Fcreate(%s) failed, error %d", name, mint_errno));
  429.         return mint_errno;
  430.     }
  431.     proc->handle[i] = f;
  432.     proc->fdflags[i] = FD_CLOEXEC;
  433.     i += offset;
  434.     TRACE(("Fcreate: returning %d", i));
  435.     return i;
  436. }
  437.  
  438. long ARGS_ON_STACK
  439. f_close(fh)
  440.     int fh;
  441. {
  442.     FILEPTR *f;
  443.     long r;
  444.     PROC *proc;
  445.  
  446.     TRACE(("Fclose: %d", fh));
  447. #if O_GLOBAL
  448.     if (fh >= 100) {
  449.         fh -= 100;
  450.         proc = rootproc;
  451.     }
  452.     else
  453. #endif
  454.         proc = curproc;
  455.  
  456.     if (fh < 0 || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  457.         return EIHNDL;
  458.     }
  459.     r = do_pclose(proc, f);
  460.  
  461. /* standard handles should be restored to default values */
  462. /* do this for TOS domain only! */
  463.     if (proc->domain == DOM_TOS) {
  464.         if (fh == 0 || fh == 1)
  465.             f = proc->handle[-1];
  466.         else if (fh == 2 || fh == 3)
  467.             f = proc->handle[-fh];
  468.         else
  469.             f = 0;
  470.     } else
  471.         f = 0;
  472.  
  473.     if (f) {
  474.         f->links++;
  475.         proc->fdflags[fh] = 0;
  476.     }
  477.     proc->handle[fh] = f;
  478.     return r;
  479. }
  480.  
  481. long ARGS_ON_STACK
  482. f_read(fh, count, buf)
  483.     int fh;
  484.     long count;
  485.     char *buf;
  486. {
  487.     FILEPTR *f;
  488.  
  489.     PROC *proc;
  490.  
  491. #if O_GLOBAL
  492.     if (fh >= 100) {
  493.         fh -= 100;
  494.         proc = rootproc;
  495.     }
  496.     else
  497. #endif
  498.         proc = curproc;
  499.  
  500.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  501.         DEBUG(("Fread: invalid handle: %d", fh));
  502.         return EIHNDL;
  503.     }
  504.     if ( (f->flags & O_RWMODE) == O_WRONLY ) {
  505.         DEBUG(("Fread: read on a write-only handle"));
  506.         return EACCDN;
  507.     }
  508.     if (is_terminal(f))
  509.         return tty_read(f, buf, count);
  510.  
  511.     TRACELOW(("Fread: %ld bytes from handle %d to %lx", count, fh, buf));
  512.     return (*f->dev->read)(f, buf, count);
  513. }
  514.  
  515. long ARGS_ON_STACK
  516. f_write(fh, count, buf)
  517.     int fh;
  518.     long count;
  519.     const char *buf;
  520. {
  521.     FILEPTR *f;
  522.     PROC *proc;
  523.     long r;
  524.  
  525. #if O_GLOBAL
  526.     if (fh >= 100) {
  527.         fh -= 100;
  528.         proc = rootproc;
  529.     }
  530.     else
  531. #endif
  532.         proc = curproc;
  533.  
  534.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  535.         DEBUG(("Fwrite: bad handle: %d", fh));
  536.         return EIHNDL;
  537.     }
  538.     if ( (f->flags & O_RWMODE) == O_RDONLY ) {
  539.         DEBUG(("Fwrite: write on a read-only handle"));
  540.         return EACCDN;
  541.     }
  542.     if (is_terminal(f))
  543.         return tty_write(f, buf, count);
  544.  
  545.     /* it would be faster to do this in the device driver, but this
  546.      * way the drivers are easier to write
  547.      */
  548.     if (f->flags & O_APPEND) {
  549.         r = (*f->dev->lseek)(f, 0L, SEEK_END);
  550.         /* ignore errors from unseekable files (e.g. pipes) */
  551.         if (r == EACCDN)
  552.             r = 0;
  553.     } else
  554.         r = 0;
  555.     if (r >= 0) {
  556.         TRACELOW(("Fwrite: %ld bytes to handle %d", count, fh));
  557.         r = (*f->dev->write)(f, buf, count);
  558.     }
  559.     if (r < 0) {
  560.         DEBUG(("Fwrite: error %ld", r));
  561.     }
  562.     return r;
  563. }
  564.  
  565. long ARGS_ON_STACK
  566. f_seek(place, fh, how)
  567.     long place;
  568.     int fh;
  569.     int how;
  570. {
  571.     FILEPTR *f;
  572.     PROC *proc;
  573.  
  574.     TRACE(("Fseek(%ld, %d) on handle %d", place, how, fh));
  575. #if O_GLOBAL
  576.     if (fh >= 100) {
  577.         fh -= 100;
  578.         proc = rootproc;
  579.     }
  580.     else
  581. #endif
  582.         proc = curproc;
  583.  
  584.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  585.         DEBUG(("Fseek: bad handle: %d", fh));
  586.         return EIHNDL;
  587.     }
  588.     if (is_terminal(f)) {
  589.         return 0;
  590.     }
  591.     return (*f->dev->lseek)(f, place, how);
  592. }
  593.  
  594. /* duplicate file pointer fh; returns a new file pointer >= min, if
  595.    one exists, or ENHNDL if not. called by f_dup and f_cntl
  596.  */
  597.  
  598. static long do_dup(fh, min)
  599.     int fh, min;
  600. {
  601.     FILEPTR *f;
  602.     int i;
  603.     PROC *proc;
  604.  
  605.     for (i = min; i < MAX_OPEN; i++) {
  606.         if (!curproc->handle[i])
  607.             goto found;
  608.     }
  609.     return ENHNDL;        /* no more handles */
  610. found:
  611. #if O_GLOBAL
  612.     if (fh >= 100) {
  613.         fh -= 100;
  614.         proc = rootproc;
  615.     } else
  616. #endif
  617.         proc = curproc;
  618.  
  619.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh]))
  620.         return EIHNDL;
  621.  
  622.     curproc->handle[i] = f;
  623.  
  624. /* set default file descriptor flags */
  625.     if (i >= 0) {
  626.         if (i >= MIN_OPEN)
  627.             curproc->fdflags[i] = FD_CLOEXEC;
  628.         else
  629.             curproc->fdflags[i] = 0;
  630.     }
  631.     f->links++;
  632.     return i;
  633. }
  634.  
  635. long ARGS_ON_STACK
  636. f_dup(fh)
  637.     int fh;
  638. {
  639.     long r;
  640.     r = do_dup(fh, MIN_OPEN);
  641.     TRACE(("Fdup(%d) -> %ld", fh, r));
  642.     return r;
  643. }
  644.  
  645. long ARGS_ON_STACK
  646. f_force(newh, oldh)
  647.     int newh;
  648.     int oldh;
  649. {
  650.     FILEPTR *f;
  651.     PROC *proc;
  652.  
  653.     TRACE(("Fforce(%d, %d)", newh, oldh));
  654.  
  655. #if O_GLOBAL
  656.     if (oldh >= 100) {
  657.         oldh -= 100;
  658.         proc = rootproc;
  659.     } else
  660. #endif
  661.         proc = curproc;
  662.  
  663.     if (oldh < MIN_HANDLE || oldh >= MAX_OPEN ||
  664.         0 == (f = proc->handle[oldh])) {
  665.         DEBUG(("Fforce: old handle invalid"));
  666.         return EIHNDL;
  667.     }
  668.  
  669.     if (newh < MIN_HANDLE || newh >= MAX_OPEN) {
  670.         DEBUG(("Fforce: new handle out of range"));
  671.         return EIHNDL;
  672.     }
  673.  
  674.     (void)do_close(curproc->handle[newh]);
  675.     curproc->handle[newh] = f;
  676.     /* set default file descriptor flags */
  677.     if (newh >= 0)
  678.         curproc->fdflags[newh] = (newh >= MIN_OPEN) ? FD_CLOEXEC : 0;
  679.     f->links++;
  680. /*
  681.  * special: for a tty, if this is becoming a control terminal and the
  682.  * tty doesn't have a pgrp yet, make it have the pgrp of the process
  683.  * doing the Fforce
  684.  */
  685.     if (is_terminal(f) && newh == -1) {
  686.         struct tty *tty = (struct tty *)f->devinfo;
  687.  
  688.         if (!tty->pgrp)
  689.             tty->pgrp = curproc->pgrp;
  690.     }
  691.     return 0;
  692. }
  693.  
  694. long ARGS_ON_STACK
  695. f_datime(timeptr, fh, rwflag)
  696.     short *timeptr;
  697.     int fh;
  698.     int rwflag;
  699. {
  700.     FILEPTR *f;
  701.     PROC *proc;
  702.  
  703.     TRACE(("Fdatime(%d)", fh));
  704. #if O_GLOBAL
  705.     if (fh >= 100) {
  706.         fh -= 100;
  707.         proc = rootproc;
  708.     }
  709.     else
  710. #endif
  711.         proc = curproc;
  712.  
  713.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  714.         DEBUG(("Fdatime: invalid handle"));
  715.         return EIHNDL;
  716.     }
  717.  
  718. /* some programs use Fdatime to test for TTY devices */
  719.     if (is_terminal(f))
  720.         return EACCDN;
  721.  
  722.     return (*f->dev->datime)(f, timeptr, rwflag);
  723. }
  724.  
  725. long ARGS_ON_STACK
  726. f_lock(fh, mode, start, length)
  727.     int fh, mode;
  728.     long start, length;
  729. {
  730.     FILEPTR *f;
  731.     struct flock lock;
  732.     PROC *proc;
  733.  
  734. #if O_GLOBAL
  735.     if (fh >= 100) {
  736.         fh -= 100;
  737.         proc = rootproc;
  738.     }
  739.     else
  740. #endif
  741.         proc = curproc;
  742.  
  743.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  744.         DEBUG(("Flock: invalid handle"));
  745.         return EIHNDL;
  746.     }
  747.     TRACE(("Flock(%d,%d,%ld,%ld)", fh, mode, start, length));
  748.     lock.l_whence = SEEK_SET;
  749.     lock.l_start = start;
  750.     lock.l_len = length;
  751.  
  752.     if (mode == 0)        /* create a lock */
  753.         lock.l_type = F_WRLCK;
  754.     else if (mode == 1)    /* unlock region */
  755.         lock.l_type = F_UNLCK;
  756.     else
  757.         return EINVFN;
  758.  
  759.     return (*f->dev->ioctl)(f, F_SETLK, &lock);
  760. }
  761.  
  762. /*
  763.  * extensions to GEMDOS:
  764.  */
  765.  
  766. /*
  767.  * Fpipe(int *handles): opens a pipe. if successful, returns 0, and
  768.  * sets handles[0] to a file descriptor for the read end of the pipe
  769.  * and handles[1] to one for the write end.
  770.  */
  771.  
  772. long ARGS_ON_STACK
  773. f_pipe(usrh)
  774.     short *usrh;
  775. {
  776.     FILEPTR *in, *out;
  777.     static int pipeno = 0;
  778.     int i, j;
  779.     char pipename[32]; /* MAGIC: 32 >= strlen "u:\pipe\sys$pipe.000\0" */
  780.  
  781.     TRACE(("Fpipe"));
  782.  
  783. /* BUG: more than 999 open pipes hangs the system */
  784.     do {
  785.         ksprintf(pipename, "u:\\pipe\\sys$pipe.%03d", pipeno);
  786.         pipeno++; if (pipeno > 999) pipeno = 0;
  787.         out = do_open(pipename, O_WRONLY|O_CREAT|O_EXCL, FA_RDONLY|FA_HIDDEN|FA_CHANGED,
  788.                  (XATTR *)0);
  789.             /* read-only attribute means unidirectional fifo */
  790.             /* hidden attribute means check for broken pipes */
  791.             /* changed attribute means act like Unix fifos */
  792.     } while (out == 0 && mint_errno == EACCDN);
  793.  
  794.     if (!out) {
  795.         DEBUG(("Fpipe: error %d", mint_errno));
  796.         return mint_errno;
  797.     }
  798.  
  799.     in = do_open(pipename, O_RDONLY, 0, (XATTR *)0);
  800.     if (!in) {
  801.         DEBUG(("Fpipe: in side of pipe not opened (error %d)",
  802.             mint_errno));
  803.         (void)do_close(out);
  804.         return mint_errno;
  805.     }
  806.  
  807.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  808.         if (curproc->handle[i] == 0)
  809.             break;
  810.     }
  811.  
  812.     for (j = i+1; j < MAX_OPEN; j++) {
  813.         if (curproc->handle[j] == 0)
  814.             break;
  815.     }
  816.  
  817.     if (j >= MAX_OPEN) {
  818.         DEBUG(("Fpipe: not enough handles left"));
  819.         (void) do_close(in);
  820.         (void) do_close(out);
  821.         return ENHNDL;
  822.     }
  823.     curproc->handle[i] = in; curproc->handle[j] = out;
  824. /* leave pipes open across Pexec */
  825.     curproc->fdflags[i] = 0;
  826.     curproc->fdflags[j] = 0;
  827.  
  828.     usrh[0] = i;
  829.     usrh[1] = j;
  830.     TRACE(("Fpipe: returning 0: input %d output %d",i,j));
  831.     return 0;
  832. }
  833.  
  834. /*
  835.  * f_cntl: a combination "ioctl" and "fcntl". Some functions are
  836.  * handled here, if they apply to the file descriptors directly
  837.  * (e.g. F_DUPFD) or if they're easily translated into file system
  838.  * functions (e.g. FSTAT). Others are passed on to the device driver
  839.  * via dev->ioctl.
  840.  */
  841.  
  842. long ARGS_ON_STACK
  843. f_cntl(fh, arg, cmd)
  844.     int fh;
  845.     long arg;
  846.     int cmd;
  847. {
  848.     FILEPTR    *f;
  849.     PROC *proc;
  850.     struct flock *fl;
  851.     long r;
  852.  
  853.     TRACE(("Fcntl(%d, cmd=0x%x)", fh, cmd));
  854. #if O_GLOBAL
  855.     if (fh >= 100) {
  856.         fh -= 100;
  857.         proc = rootproc;
  858.     }
  859.     else
  860. #endif
  861.         proc = curproc;
  862.  
  863.     if (fh < MIN_HANDLE || fh >= MAX_OPEN) {
  864.         DEBUG(("Fcntl: bad file handle"));
  865.         return EIHNDL;
  866.     }
  867.  
  868.     if (cmd == F_DUPFD) {
  869. #if O_GLOBAL
  870.         if (proc != curproc) fh += 100;
  871. #endif
  872.           return do_dup(fh, (int)arg);
  873.     }
  874.  
  875.     f = proc->handle[fh];
  876.     if (!f) return EIHNDL;
  877.  
  878.     switch(cmd) {
  879.     case F_GETFD:
  880.         TRACE(("Fcntl F_GETFD"));
  881.         if (fh < 0) return EIHNDL;
  882.         return proc->fdflags[fh];
  883.     case F_SETFD:
  884.         TRACE(("Fcntl F_SETFD"));
  885.         if (fh < 0) return EIHNDL;
  886.         proc->fdflags[fh] = arg;
  887.         return 0;
  888.     case F_GETFL:
  889.         TRACE(("Fcntl F_GETFL"));
  890.         return f->flags & O_USER;
  891.     case F_SETFL:
  892.         TRACE(("Fcntl F_SETFL"));
  893.         arg &= O_USER;        /* make sure only user bits set */
  894. #if 0
  895.     /* COMPATIBILITY WITH OLD VERSIONS ONLY */
  896.     /* THIS CODE WILL GO AWAY. REALLY! */
  897.         if (arg & 4) {
  898.             arg |= O_NDELAY;
  899.             arg &= ~4;
  900.         }
  901. #endif
  902.  
  903.     /* make sure the file access and sharing modes are not changed */
  904.         arg &= ~(O_RWMODE|O_SHMODE);
  905.         arg |= f->flags & (O_RWMODE|O_SHMODE);
  906.         f->flags &= ~O_USER;    /* set user bits to arg */
  907.         f->flags |= arg;
  908.         return 0;
  909.     case FSTAT:
  910.         return (*f->fc.fs->getxattr)(&f->fc, (XATTR *)arg);
  911.     case F_SETLK:
  912.     case F_SETLKW:
  913.     /* make sure that the file was opened with appropriate permissions */
  914.         fl = (struct flock *)arg;
  915.         if (fl->l_type == F_RDLCK) {
  916.             if ( (f->flags & O_RWMODE) == O_WRONLY )
  917.                 return EACCDN;
  918.         } else {
  919.             if ( (f->flags & O_RWMODE) == O_RDONLY )
  920.                 return EACCDN;
  921.         }
  922.         /* fall through to device ioctl */
  923.     default:
  924.         TRACE(("Fcntl mode %x: calling ioctl",cmd));
  925.         r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  926.         if (r == EINVFN && is_terminal(f)) {
  927.             r = tty_ioctl(f, cmd, (void *)arg);
  928.         }
  929.         return r;
  930.     }
  931. }
  932.  
  933. /*
  934.  * fselect(timeout, rfd, wfd, xfd)
  935.  * timeout is an (unsigned) 16 bit integer giving the maximum number
  936.  * of milliseconds to wait; rfd, wfd, and xfd are pointers to 32 bit
  937.  * integers containing bitmasks that describe which file descriptors
  938.  * we're interested in. These masks are changed to represent which
  939.  * file descriptors actually have data waiting (rfd), are ready to
  940.  * output (wfd), or have exceptional conditions (xfd -- currently
  941.  * ignored). If timeout is 0, fselect blocks until some file descriptor
  942.  * is ready; otherwise, it waits only "timeout" milliseconds.
  943.  * Return value: number of file descriptors that are available for
  944.  * reading/writing; or a negative error number.
  945.  */
  946.  
  947. /* helper function for time outs */
  948. static void
  949. unselectme(p)
  950.     PROC *p;
  951. {
  952.     wakeselect((long)p);
  953. }
  954.  
  955. long ARGS_ON_STACK
  956. f_select(timeout, rfdp, wfdp, xfdp)
  957.     unsigned timeout;
  958.     long *rfdp, *wfdp, *xfdp;
  959. {
  960.     long rfd, wfd;
  961.     long mask, bytes;
  962.     int i, count;
  963.     FILEPTR *f;
  964.     PROC *p;
  965.     TIMEOUT *t;
  966.     short sr;
  967.  
  968.     if (xfdp)
  969.         *xfdp = 0;
  970.  
  971.     if (rfdp) {
  972.         rfd = *rfdp; *rfdp = 0;
  973.     }
  974.     else
  975.         rfd = 0;
  976.     if (wfdp) {
  977.         wfd = *wfdp; *wfdp = 0;
  978.     }
  979.     else
  980.         wfd = 0;
  981.  
  982.     TRACE(("Fselect(%u, %lx, %lx)", timeout, rfd, wfd));
  983.     p = curproc;            /* help the optimizer out */
  984.  
  985.     /* first, validate the masks */
  986.     mask = 1L;
  987.     for (i = 0; i < MAX_OPEN; i++) {
  988.         if ( ((rfd & mask) || (wfd & mask)) && !(p->handle[i]) ) {
  989.             DEBUG(("Fselect: invalid handle: %d", i));
  990.             return EIHNDL;
  991.         }
  992.         mask = mask << 1L;
  993.     }
  994.  
  995. /* now, loop through the file descriptors, setting up the select process */
  996. /* NOTE: wakeselect will set p->wait_cond to 0 if data arrives during the
  997.  * selection
  998.  * Also note: because of the validation above, we may assume that the
  999.  * file handles are valid here. However, this assumption may no longer
  1000.  * be true after we've gone to sleep, since a signal handler may have
  1001.  * closed one of the handles.
  1002.  */
  1003.  
  1004.     mask = 1L;
  1005.     count = 0;
  1006.     curproc->wait_cond = (long)wakeselect;        /* flag */
  1007.  
  1008.     for (i = 0; i < MAX_OPEN; i++) {
  1009.         if (rfd & mask) {
  1010.             f = p->handle[i];
  1011.             if ((*f->dev->select)(f, (long)p, O_RDONLY)) {
  1012.                 count++;
  1013.                 *rfdp |= mask;
  1014.             }
  1015.         }
  1016.         if (wfd & mask) {
  1017.             f = p->handle[i];
  1018.             if ((*f->dev->select)(f, (long)p, O_WRONLY)) {
  1019.                 count++;
  1020.                 *wfdp |= mask;
  1021.             }
  1022.         }
  1023.         mask = mask << 1L;
  1024.     }
  1025.  
  1026.     if (count == 0) {
  1027.         /* OK, now let's set a timeout */
  1028.  
  1029.         if (timeout) {
  1030.             t = addtimeout((long)timeout, unselectme);
  1031.         } else {
  1032.             t = 0;
  1033.         }
  1034.  
  1035.         sr = spl7();
  1036.  
  1037.     /* curproc->wait_cond changes when data arrives or the timeout happens */
  1038.         while (curproc->wait_cond == (long)wakeselect) {
  1039.             TRACE(("sleeping in Fselect"));
  1040.             sleep(SELECT_Q, (long)wakeselect);
  1041.         }
  1042.         spl(sr);
  1043.  
  1044.     /* we can cancel the time out now (if it hasn't already happened) */
  1045.         if (t) canceltimeout(t);
  1046.  
  1047.     /* OK, let's see what data arrived (if any) */
  1048.         mask = 1L;
  1049.         for (i = 0; i < MAX_OPEN; i++) {
  1050.             if (rfd & mask) {
  1051.                 f = p->handle[i];
  1052.                 if (f) {
  1053.                     bytes = 1L;
  1054.                     (void)(*f->dev->ioctl)(f, FIONREAD,&bytes);
  1055.                     if (bytes > 0) {
  1056.                     *rfdp |= mask;
  1057.                     count++;
  1058.                     }
  1059.                 }
  1060.             }
  1061.             if (wfd & mask) {
  1062.                 f = p->handle[i];
  1063.                 if (f) {
  1064.                     bytes = 1L;
  1065.                     (void)(*f->dev->ioctl)(f, FIONWRITE,&bytes);
  1066.                     if (bytes > 0) {
  1067.                     *wfdp |= mask;
  1068.                     count++;
  1069.                     }
  1070.                 }
  1071.             }
  1072.             mask = mask << 1L;
  1073.         }
  1074.     }
  1075.  
  1076.     /* at this point, we either have data or a time out */
  1077.     /* cancel all the selects */
  1078.     mask = 1L;
  1079.  
  1080.     for (i = 0; i < MAX_OPEN; i++) {
  1081.         if (rfd & mask) {
  1082.             f = p->handle[i];
  1083.             if (f)
  1084.                 (*f->dev->unselect)(f, (long)p, O_RDONLY);
  1085.         }
  1086.         if (wfd & mask) {
  1087.             f = p->handle[i];
  1088.             if (f)
  1089.                 (*f->dev->unselect)(f, (long)p, O_WRONLY);
  1090.         }
  1091.         mask = mask << 1L;
  1092.     }
  1093.  
  1094.     TRACE(("Fselect: returning %d", count));
  1095.     return count;
  1096. }
  1097.  
  1098.  
  1099. /*
  1100.  * GEMDOS extension: Fmidipipe
  1101.  * Fmidipipe(pid, in, out) manipultes the MIDI file handles (handles -4 and -5)
  1102.  * of process "pid" so that they now point to the files with handles "in" and
  1103.  * "out" in the calling process
  1104.  */
  1105.  
  1106. long ARGS_ON_STACK
  1107. f_midipipe(pid, in, out)
  1108.     int pid, in, out;
  1109. {
  1110.     PROC *p;
  1111.     FILEPTR *fin, *fout;
  1112.  
  1113. /* first, find the process */
  1114.  
  1115.     if (pid == 0)
  1116.         p = curproc;
  1117.     else {
  1118.         p = pid2proc(pid);
  1119.         if (!p)
  1120.             return EFILNF;
  1121.     }
  1122.  
  1123. /* next, validate the input and output file handles */
  1124.     if (in < MIN_HANDLE || in >= MAX_OPEN || (0==(fin = curproc->handle[in])))
  1125.         return EIHNDL;
  1126.     if ( (fin->flags & O_RWMODE) == O_WRONLY ) {
  1127.         DEBUG(("Fmidipipe: input side is write only"));
  1128.         return EACCDN;
  1129.     }
  1130.     if (out < MIN_HANDLE || out >= MAX_OPEN || (0==(fout = curproc->handle[out])))
  1131.         return EIHNDL;
  1132.     if ( (fout->flags & O_RWMODE) == O_RDONLY ) {
  1133.         DEBUG(("Fmidipipe: output side is read only"));
  1134.         return EACCDN;
  1135.     }
  1136.  
  1137. /* OK, duplicate the handles and put them in the new process */
  1138.     fin->links++; fout->links++;
  1139.     (void)do_pclose(p, p->midiin);
  1140.     (void)do_pclose(p, p->midiout);
  1141.     p->midiin = fin; p->midiout = fout;
  1142.     return 0;
  1143. }
  1144.